This article will explain how to write programs that use Econet as a device, rather than just as a filing system.
Econet_CreateReceive Econet_ExamineReceive Econet_AbandonReceive Econet_WaitForReception Econet_DoTransmit Econet_ReadLocalStationAndNet
These names are fairly obvious.
DIM rxcb% 2048
This however will not work unless your program is non-multitasking, the reason being that data is read by RISC OS itself, not the application. The Econet module within RISC OS will attempt to write to the address given, but because the MEMC has remapped it will overwrite another application and may cause a complete system crash.
The solution is to claim workspace in the RMA. The following SWI will do the trick:
SYS "OS_Module",6,,,2048 TO rxcb%
You can define your transmit buffer in the normal way, ie:
DIM txcb% 2048
as RISC OS makes a copy of the transmit block before starting the transmit operation.
Next we need to add some library procedures:
PROCgetstationaddress FNcreaterx FNgetrxdata FNrxstatus FNwaitforrx PROCtransmit
DEFPROCgetstationaddress(RETURN net%,RETURN station%) SYS "Econet_ReadLocalStationAndNet" TO station%,net% ENDPROC
It should be called as your program is initialising, like this:
net%=0 station%=0 PROCgetstationaddress(net%,station)
Now on to the receive functions. FNcreaterx will create a receive block, returning the block handle:
DEFFNcreaterx(port%,station%,net%) LOCAL rxhandle% SYS "Econet_CreateReceive",port%,station%,net%,rxcb%,2048 TO rxhandle% =rxhandle%
FNgetrxdata reads back any received data from the given block handle as a string:
DEFFNgetrxdata(rxhandle%) LOCAL rxdata%,bytes%,rxdata$ SYS "Econet_ReadReceive",rxhandle% TO ,,,,,rxdata%,bytes% rxdata%?bytes%=13 rxdata$=$rxdata% SYS "Econet_AbandonReceive",rxhandle% =rxdata$
FNrxstatus will return TRUE if data has been received on the given handle or FALSE if either no data has been received or a reception is currently in progress:
DEFFNrxstatus(rxhandle%) LOCAL status% SYS "Econet_ExamineReceive",rxhandle% TO status% IF status%=9 =TRUE ELSE =FALSE
The final receive function, FNwaitforrx, will wait until either data is received from the given station and port number or a specified timeout (in centiseconds) is reached, in which case it will return a null string.
DEFFNwaitforrx(port%,station%,net%,time%) LOCAL rxhandle%,rxdata%,bytes%,status% SYS "Econet_CreateReceive",port%,station%,net%,rxcb%,2048 TO rxhandle% SYS "Econet_WaitForReception",rxhandle%,time%,0 TO status%,,,,,rxdata%,bytes% IF status%=10 ="" rxdata%?bytes%=13 =$rxdata%
DEFPROCtransmit(port%,station%,net%,txdata$) $txcb%=txdata$ SYS "Econet_DoTransmit",0,port%,station%,net%,txcb%,LEN(txdata$),64,2 ENDPROC
The last 2 numbers on the DoTransmit SWI are the number of retries and the delay between retries in centiseconds; in this example it will try 64 times to transmit with a 2 cenisecond delay between each attempt.
Ok, that's all very well, but how do you use them?
The best way is, as ever, to have a very short example program. It will multitask, but will not have any windows, icons or menus. It will simply record everything transmitted on port 128 into a file in the CSD.
Note that if you specify to receive from station 0, you will be able to receive from any station on your network (ie not from across a bridge).
Yes, I know this doesn't comply with the style guide, but it's only a demonstration!
DIM taskid% 4,block% 2048 $taskid%="TASK" SYS "OS_Module",6,,,2048 TO ,,rxcb% SYS "Wimp_Initialise",200,!taskid%,"Econet demo" quit%=FALSE station%=0 net%=0 port%=128 rxhandle%=FNcreaterx(port%,station%,net%) file%=OPENOUT"NetData" REPEAT SYS "Wimp_Poll,,block% TO action% CASE action% OF WHEN 0 : IF FNrxstatus THEN PROCdatareceived WHEN 17,18 : IF block%!16=0 quit%=TRUE ENDCASE UNTIL quit% CLOSE#file% IF rxcb%<>-1 THEN SYS "XOS_Module",7,,rxcb% END
You will need to add the procedure PROCdatareceived to the program later, but first a quick description.
The first few lines are just a standard WIMP application header, the third line claims workspace from RMA. Notice that you should set up the receive block before the start of the main polling loop, otherwise you will get an "Unknown or missing variable" error.
When the WIMP returns control with a reason code of 0 (ie a null poll) this is when you chech the state of the receive block with FNrxstatus. If the result returns TRUE it calls the procedure PROCdatareceived, which we shall come to in a short time.
You can quit this program from the Task Manager (reason codes 17 and 18), the final line before the END releases the workspace we claimed earlier back to the RMA.
Now for the procedure PROCdatareceived:
DEFPROCdatareceived LOCAL rxdata$ rxdata$=FNgetrxdata(rxhandle%) rxhandle%=FNcreaterx%(port%,station%,net%) BPUT#file%,rxdata$ ENDPROC
This is fairly straightforward, but notice the requirement to create a new receive block immediately after reading out the data. This is because once the block has been filled a new one must be created before any new data can be received.
Once the new block has been created it then writes out the received string to the file that was opened at the start of the program.
To demonstrate that it's working we shall need a transmit program, this is a very simple single-tasking affair:
MODE 12 DIM txcb% 2048 port%=128 net%=0 INPUT "Enter station number"station% REPEAT INPUT txdata$ PROCtransmit(port%,station%,net%,txdata$) UNTIL FALSE
Attach PROCtransmit above to the end of this program and run it on another station somewhere, and whatever you type should be saved into the file. Press ESCAPE to quit the transmit program.